// 守护进程
#pragma once

#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>


// 守护进程是脱离控制终端，在后台长期运行的进程，不受用户注销/登陆影响
// 有独立的会话和进程组，通常从根目录作为工作目录，标准输入重定向到/dev/null

#define ROOT "/"
#define Devnull "/dev/null" // 任何写入的数据都会被丢弃，相当于数据黑洞

void Daemon(bool ischdir, bool isclose)
{
	// 1.守护进程一般要屏蔽掉特定信号
	signal(SIGCHLD, SIG_IGN); // 子进程退出时父进程会收到信号，避免产生僵尸进程
	signal(SIGPIPE, SIG_IGN); // 写入一个已经关闭的管道时触发

	// 2.成为非组长
	if (fork() > 0)
		exit(0);

	// 3.建立新会话
	setsid();

	// 4.每一个进程都有自己的CWD,是否将当前进程的CWD更改为根目录
	if (ischdir)
		chdir(ROOT);

	// 5.已经成为守护进程，不需要和用户的输入输出，错误进行关联了
	if (isclose)
	{
		::close(0);
		::close(1);
		::close(2);
	}
	else
	{
		int fd = ::open(Devnull, O_WRONLY);
		if (fd > 0)
		{
			// 重定向
			dup2(fd, 0);
			dup2(fd, 1);
			dup2(fd, 2);
			close(fd);
		}
	}
}